#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <functional>
#include "InetAddr.hpp"

using func_t=std::function<void(int, const std::string&,InetAddr&)>;
//using func_t=std::function<std::string(const std::string)>;


class udpserver
{
    public:
    udpserver(uint16_t port,func_t func)
    :_port(port), 
    _isrunning(false),
    _func(func)
    {}
    //////////////////////////////////
    void init()
    {
        //1，创建套接字
        _sockfd=socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
            std::cout<<"创建套接字失败"<<std::endl;
            exit(1);
        }
        std::cout<<"创建套接字成功"<<std::endl;

        //2,绑定端口号和IP
        //填充sockarr_in信息
        struct sockaddr_in local;
        //先将结构体内容清0
        bzero(&local,sizeof(local));
        local.sin_family=AF_INET;//头部的16为，表示网络通信
        local.sin_port=htons(_port);//端口号
        //INADDR_ANY是一个宏，这个宏的值是0
        //可能存在多个客户端要访问该服务器进程
        //有的客户端拿着内网IP，有的客户端拿着本地回环IP 127.0.0.1访问该服务器进程
        //那么该服务器进程的IP就必须保持不变，是一个绑死的值，只有和该IP相等的客户端才能访问
        //将IP地址设为0的好处是：
        //不同的客户端，拿着不同的IP访问该服务器进程，只要端口号和该进程相等，就都可以访问呢
        local.sin_addr.s_addr=INADDR_ANY;//IP地址
        int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            std::cout<<"绑定失败"<<std::endl;
            exit(2);
        }
        std::cout<<"绑定成功"<<std::endl;
    }
    void start()
    {
        _isrunning=true;
        while(_isrunning)
        {
            //缓冲区——存放消息
            char buffer[1024];
            //获取哪台主机的哪个进程发送的数据，可以理解为这是一个输出型参数
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            //接受消息
            //我们将接受到的消息是按字符串存储的
            //这里sizeof(buffer)-1是为了保留最后一个位置填充‘0’
            ssize_t s=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
            if(s>0)
            {
                InetAddr client(peer);
                buffer[s] = 0;

                _func(_sockfd, buffer, client);
                //_func("11111111");

                //发送消息
                //sendto(_sockfd,result.c_str(),result.size(),0,(struct sockaddr*)&peer,len);
            }

        }
    }
    /////////////////////////////////
    ~udpserver()
    {}
    private:
    int _sockfd;//套接字
    uint16_t _port;//端口号
    bool _isrunning;//是否在进行网络通信
    func_t _func;//回调函数
};